/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-24
 * Time: 23:01
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Generic;

using tools;
using patterns;

using Labb4.Main;
using Labb4.Entity;
using Labb4.Event;
using Labb4.Pooman.Players;
using Labb4.Pooman.Cards;
using Labb4.Pooman.Misc;
using Labb4.Rules;

namespace Labb4.Pooman.Game
{
	/// <summary>
	/// This is the main part of the game logic. All major decissions comes from an instance
	/// of this class. It is not made a singleotn in itself, but when an instance is created
	/// it is registered with the singleton class PoomanRules. This makes the instance of this
	/// class accessible everywhere in the program, as long as an instance of this class has
	/// actually been created.
	/// 
	/// Implements the Observer design pattern
	/// This class is the SubjectForObservation for all game components
	/// </summary>
	public class PoomanMain : SubjectForObservation<GameState>, IManager //facade, observer
	{
		#region members
		
		/// <summary>
		/// The card deck of the game
		/// </summary>
		private Deck				m_Deck;
		/// <summary>
		/// Reference to the input manager
		/// </summary>
		private InputManager		m_InputManager;
		
		/// <summary>
		/// The computer player playing with the suit strategy
		/// </summary>
		private Player				m_AiSuitPlayer;
		/// <summary>
		/// The computer player playing with the value strategy
		/// </summary>
		private Player				m_AiValuePlayer;
		/// <summary>
		/// The player controled by ... the player
		/// </summary>
		private Player				m_Player1;
		
		/// <summary>
		/// The first phase of the game
		/// </summary>
		private GameStatePhase1		m_Phase1;
		/// <summary>
		/// The second phase of the gane
		/// </summary>
		private GameStatePhase2		m_Phase2;
		
		/// <summary>
		/// The minimum number of cards in the deck allowed to still be able to draw/deal a card from the deck
		/// </summary>
		private int					m_MinimumNumberOfCardsInDeck;
		/// <summary>
		/// How the Ai's cards should be displayed (normal or hidden)
		/// </summary>
		private string				StandardDisplayModeForAiCards;
		
		/// <summary>
		/// The current trump
		/// </summary>
		private Trump				m_Trump;
		/// <summary>
		/// When the trump card is discovered, it's stored here
		/// </summary>
		private Card				m_TrumpCard;
		/// <summary>
		/// A reference to the player who was the one who discovered the trump
		/// </summary>
		private Player				m_PlayerWhoTookTheTrump;
		
		/// <summary>
		/// For the manager, to see if the class has been initialized or not
		/// </summary>
		private bool				m_WasInitialized;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members, creates players with their different ai strategies,
		/// registers all observers to subscribe to this instance.
		/// </summary>
		public PoomanMain() :
			base()
		{
			m_Deck = null;
			
			m_InputManager = InputManager.Instance;
			Table.Instance.Subscribe(this);
			
			PoomanControl player = new PoomanPlayerControl();
			m_Player1 = new Player(player, Table.Instance.BottomArea);
			ControlManager.Instance.SetPlayer1Control(player);
			
			AiStrategy aiStrategySuit = new AiStrategySuit();
			aiStrategySuit.Subscribe(this);
			PoomanAiControl aiSuit = new PoomanAiControl(aiStrategySuit);
			m_AiSuitPlayer = new Player(aiSuit, Table.Instance.LeftArea);
			
			AiStrategy aiStrategyValue = new AiStrategyValue();
			aiStrategyValue.Subscribe(this);
			PoomanAiControl aiValue = new PoomanAiControl(aiStrategyValue);
			m_AiValuePlayer = new Player(aiValue, Table.Instance.RightArea);
			
			m_Phase1 = new GameStatePhase1(this);
			m_Phase2 = new GameStatePhase2(this);
			
			m_MinimumNumberOfCardsInDeck = 2;
			StandardDisplayModeForAiCards = "hidden";
			
			m_Trump = new Trump();
			m_TrumpCard = null;
			m_PlayerWhoTookTheTrump = null;
			
			m_WasInitialized = false;
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Deals one card to a player, and displays this card on the table after some time
		/// </summary>
		/// <param name="player">The player who should have the card</param>
		/// <param name="delay">The delay before displaying the card. Unit is (ms)</param>
		/// <returns></returns>
		public bool DealOneCardToPlayer(Player player, int delay)
		{
			bool dealtCard = false;
			
			if(State is GameStatePhase1)
			{
				if(m_Deck.Count < m_MinimumNumberOfCardsInDeck)
				{
					//give trump card to player
					if(m_Deck.Count > 0)
					{
						m_PlayerWhoTookTheTrump = player;
						m_TrumpCard = m_Deck.GetTopCard();
						m_TrumpCard.GraphicalRepresentation.Pic.Activate(0, delay);
						m_TrumpCard.GraphicalRepresentation.Pic.SelectAnimation("hidden");
						player.HandPhase2.Cards.Add(m_TrumpCard);
						
						m_Trump.SetTrump(m_TrumpCard);
						
						int x = 100;
						int y = 50;
						
						if(m_PlayerWhoTookTheTrump == m_Player1)
						{
							x = 300;
							y = 400;
						}
						
						if(m_PlayerWhoTookTheTrump == m_AiSuitPlayer)
						{
						}
						
						if(m_PlayerWhoTookTheTrump == m_AiValuePlayer)
						{
							x = 500;
						}
						
						m_TrumpCard.GraphicalRepresentation.Pic.Xpos = x;
						m_TrumpCard.GraphicalRepresentation.Pic.Ypos = y;
					}
				}
				else
				{
					dealtCard = true;
					string display = StandardDisplayModeForAiCards;
					
					if(player == m_Player1)
					{
						display = "normal";
					}
					
					Card card = m_Deck.GetTopCard();
					card.GraphicalRepresentation.Pic.Activate(0, delay);
					card.GraphicalRepresentation.Pic.SelectAnimation(display);
					player.CurrentHand.Cards.Add(card);
					
					Event.Event dealEvent = null;
					string eventNamePart1 = Properties.Instance.StartPath + "resources\\configfiles\\events\\event_deal_";
					string eventNamePart2 = "bottom";
					string eventNamePart3 = ".txt";
					
					if(player.Area == Table.Instance.LeftArea)
					{
						eventNamePart2 = "left";
					}
					
					if(player.Area == Table.Instance.RightArea)
					{
						eventNamePart2 = "right";
					}
					
					dealEvent = EventManager.Instance.GetEvent(eventNamePart1 + eventNamePart2 + eventNamePart3);
					
					if(dealEvent != null)
					{
						Event.EventHandler.Instance.AddEventToTimedQueue(dealEvent);
					}
				}
			}
			
			return dealtCard;
		}
		
		/// <summary>
		/// A player can draw and play the top card of the deck, instead of playing one of
		/// cards on hand. If there are too few cards in the deck, nothing happens
		/// </summary>
		/// <param name="player">The player drawing the chance card</param>
		/// <returns>True if the chance succeeded, otherwise false</returns>
		public bool ChanceCard(Player player)
		{
			bool chanced = false;
			Debug.WriteLine("\tAttempting chance on deck");
			
			if(player.CurrentHand.SelectedCards() == 0)
			{
				if(!(m_Deck.Count < m_MinimumNumberOfCardsInDeck))
				{
					Card chanceCard = m_Deck.GetTopCard();
					chanceCard.GraphicalRepresentation.Pic.Activate(0);
					chanceCard.GraphicalRepresentation.Pic.SelectAnimation("normal");
					chanceCard.GraphicalRepresentation.Pic.Xpos = 500;
					chanceCard.GraphicalRepresentation.Pic.Ypos = 400;
					
					chanceCard.SelectCard(true);
					player.CurrentHand.Cards.Add(chanceCard);
					
					chanced = true;
					Debug.WriteLine("\tChance card selected and played");
					Debug.Flush();
				}
			}
			else
			{
				MessageBox.Show("You can not have cards on hand selected when chancing from the deck.\nFor help press F1.", "Pooman Rulebook");
			}
			
			return chanced;
		}
		
		/// <summary>
		/// Resets the game to its initial state, thus starting a new game
		/// </summary>
		public void ResetGame()
		{
			Reset();
			
			m_Deck.Shuffle();
			m_Deck.ResetAllCards();
			
			m_Player1.SwitchToHand1();
			m_AiSuitPlayer.SwitchToHand1();
			m_AiValuePlayer.SwitchToHand1();
			
			SetSubjectsState(m_Phase1);
			State.ResetPhase(m_Player1); //TODO here it is possible to cycle what player goes first in the game
			PlayerManager.Instance.SortAndPositionCards();
			
			Event.EventHandler.Instance.AddEventAndPlay(EventManager.Instance.GetEvent(Properties.Instance.StartPath + "resources\\configfiles\\events\\event_winner_penguine.txt"));
		}
		
		/// <summary>
		/// Resets the game to a state found in a file, thus loading an old game
		/// </summary>
		/// <param name="fileName">The name of the file where the saved game recides</param>
		public void ResetGame(string fileName)
		{
			Reset();
			m_Trump.ResetTrump();
			PoomanRules.Instance.CurrentRound = null;
			PoomanRules.Instance.CurrentTrump = null;
			
			Config config = new Config();
			
			if(MainForm.ErrorCheck(config.Open(fileName)))
			{
				int phase = 0;
				
				if(MainForm.ErrorCheck(config.GetInt("phase", ref phase)))
				{
					if(phase == 1)
					{
						SetSubjectsState(m_Phase1);
					}
					
					if(phase == 2)
					{
						SetSubjectsState(m_Phase2);
						string trump = "";
						
						if(MainForm.ErrorCheck(config.GetString("trump", ref trump)))
						{
							m_Trump.SetTrump((Card.Suit)Enum.Parse(typeof(Card.Suit), trump));
							PoomanRules.Instance.CurrentTrump = m_Trump;
						}
					}
					
					PoomanRules.Instance.PrepareForLoad();
					
					m_Deck.Load(config, "deck");
					State.Load(config);
					m_Player1.Load(config, "player_1");
					m_AiSuitPlayer.Load(config, "ai_suit_player");
					m_AiValuePlayer.Load(config, "ai_value_player");
					
					PoomanRules.Instance.FinnishUpLoad();
					
					m_Player1.CurrentHand.Cards.Sort();
					m_AiSuitPlayer.CurrentHand.Cards.Sort();
					m_AiValuePlayer.CurrentHand.Cards.Sort();
				}
			}
			
			PlayerManager.Instance.SortAndPositionCards();
		}
		
		/// <summary>
		/// Saves the current game to a file
		/// </summary>
		/// <param name="fileName">The name of the file to save to</param>
		public void SaveGame(string fileName)
		{
			List<string> fileContent = new List<string>();
			
			string phase = "1";
			
			if(State is GameStatePhase2)
			{
				phase = "2";
				fileContent.Add("trump " + m_Trump.TrumpSuit.ToString());
			}
			
			fileContent.Add("phase " + phase);
			
			m_Deck.Save(fileContent, "deck", "hidden");
			State.Save(fileContent);
			m_Player1.Save(fileContent, "player_1");
			m_AiSuitPlayer.Save(fileContent, "ai_suit_player");
			m_AiValuePlayer.Save(fileContent, "ai_value_player");
			
			ListFileTool file = new ListFileTool();
			file.SaveListToFile(fileName, fileContent, true);
		}
		
		/// <summary>
		/// Switches the current game phase
		/// </summary>
		public void SwitchPhase()
		{
			if(State is GameStatePhase1)
			{
				State.LastActionOfThePhase();
				
				m_Player1.SwitchToHand2("normal");
				m_Player1.CurrentHand.Cards.Sort();
				m_Player1.PositionCards();
				
				m_AiSuitPlayer.SwitchToHand2(StandardDisplayModeForAiCards);
				m_AiSuitPlayer.CurrentHand.Cards.Sort();
				m_AiSuitPlayer.PositionCards();
				
				m_AiValuePlayer.SwitchToHand2(StandardDisplayModeForAiCards);
				m_AiValuePlayer.CurrentHand.Cards.Sort();
				m_AiValuePlayer.PositionCards();
				
				PoomanRules.Instance.CurrentTrump = m_Trump;
				string trumphShow = Properties.Instance.StartPath + "resources\\configfiles\\events\\event_trumph_is_" + m_Trump.TrumpSuit.ToString() + ".txt";
				Event.Event trumphEvent = EventManager.Instance.GetEvent(trumphShow);
				
				if(trumphEvent != null)
				{
					Event.EventHandler.Instance.AddEventAndPlay(trumphEvent);
				}
				
				Table.Instance.CardsOnTable.Clear();
				
				SetSubjectsState(m_Phase2);
				State.ResetPhase(m_PlayerWhoTookTheTrump);
			}
			else
			{
				Player pooman = PlayerManager.Instance.GetPooman();
				
				if(pooman != null)
				{
					if(pooman == m_Player1)
					{
						MessageBox.Show("You are the Pooman! :P You loose.", "Game Over");
					}
					else
					{
						MessageBox.Show("You are NOT the Pooman! :) Good for you.", "Game Over");
					}
				}
				
				ResetGame();
			}
		}
		
		#endregion
		
		#region implemented interface methods
		
		/// <summary>
		/// Initializes the instance
		/// </summary>
		public void Initialize()
		{
			if(!m_WasInitialized)
			{
				PoomanRules.Instance.MainPoo = this;
				ResetGame();
				
				m_WasInitialized = true;
			}
		}
		
		/// <summary>
		/// Tears down the instance
		/// </summary>
		public void TearDown()
		{
			if(m_WasInitialized)
			{
				m_WasInitialized = false;
			}
		}
		
		/// <summary>
		/// Updates the instance
		/// </summary>
		/// <param name="deltaTime">The time passed since the last call to update. Unit is (ms)</param>
		public void Update(ref int deltaTime)
		{
			if(m_WasInitialized)
			{
				State.PlayNextStick(deltaTime);
			}
		}
		
		#endregion
		
		#region private methods
		
		/// <summary>
		/// Resets members, clears all managers, essentially clearing the whole game and visual memory
		/// </summary>
		private void Reset()
		{
			Event.EventManager.Instance.Clear();
			EntityManager.Instance.Clear();
			ControlManager.Instance.Clear();
			
			PictureEntityFactory factory = new PictureEntityFactory();
			factory.GetProduct(Properties.Instance.StartPath + "resources\\configfiles\\background.txt").Activate(0);
			
			StandardDisplayModeForAiCards = "hidden";
			
			if(Properties.Instance.OpenCards)
			{
				StandardDisplayModeForAiCards = "normal";
			}
			
			if(m_Deck != null)
			{
				m_Deck.Remove(m_Deck);
				PlayerManager.Instance.ClearAllPlayersCards();
				Table.Instance.ClearTable();
				
				Debug.WriteLine(m_Deck.Count);
				m_Deck = new Deck();
				
				m_Trump.ResetTrump();
				PoomanRules.Instance.CurrentTrump = null;
			}
			else
			{
				m_Deck = new Deck();
			}
		}
		
		#endregion
	}
}
